package ar.camera.renderer.extend;

import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import android.content.Context;
import android.opengl.GLU;
import android.view.MotionEvent;
import ar.Location.Map.MyOverlayItem;
import ar.Location.Map.SharingLocations;
import ar.activity.ARCameraActivity;
import ar.camera.globject.LocationIcon;
import ar.camera.glsurfaceview.extend.LocationIconSurfaceView;
import ar.camera.pojo.GLLocation;
import ar.camera.pojo.GLPoint;
import ar.camera.pojo.GeoLocation;
import ar.camera.pojo.ScreenLocation;
import ar.camera.renderer.base.BaseRenderer;
import ar.globals.Globals;
import ar.utils.LocationUtils;

public class LocationIconRenderer extends BaseRenderer {

	private static LocationIcon myCurrIcon;
	private static List<LocationIcon> icons = new ArrayList<LocationIcon>();
	private List<ScreenLocation> screenLocations = new ArrayList<ScreenLocation>();
	private boolean isUpdateSensor;

	private float[] mvmatrix = new float[16];
	private float[] projmatrix = new float[16];
	private int[] viewport = new int[4];

	private ARCameraActivity arCamAc = null;

	public boolean isUpdateSensor() {
		return isUpdateSensor;
	}

	public void setUpdateSensor(boolean isUpdateSensor) {
		this.isUpdateSensor = isUpdateSensor;
	}

	public List<ScreenLocation> getListOfScreenLocations() {
		return screenLocations;
	}

	/** Constructor to set the handed over context */
	public LocationIconRenderer(Context mContext, GLPoint eye, GLPoint cam,
			ARCameraActivity ac) {
		super(mContext, eye, cam);
		isUpdateSensor = true;
		this.arCamAc = ac;
	}

	public void onDrawFrame(GL10 gl) {
		super.onDrawFrame(gl);

		GLU.gluLookAt(gl, eye.x, eye.y, eye.z, cam.x, cam.y, cam.z, 0f, 1f, 0f);

		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glFrustumf(-ratio / 3, ratio / 3, (float) -1 / 3, (float) 1 / 3,
				0.6f, 100f);

		if (icons != null) {
			for (LocationIcon li : icons) {
				if (li.isLoadedTexture() == false) {
					li.loadGLTexture(gl, this.mContext, false);
				}
				li.draw(gl);
			}
		}
		if (myCurrIcon != null) {
			if (myCurrIcon.isLoadedTexture() == false) {
				myCurrIcon.loadGLTexture(gl, this.mContext, true);
			}
			myCurrIcon.draw(gl);
		}
		screenLocations.clear();
		for (LocationIcon li : icons) {
			GLLocation gll = li.getGlLocation();
			float screenLoc[] = new float[4];
			gluGetScreenLocation(gl, gll.x, gll.y, gll.z, 0, false, screenLoc);
			ScreenLocation sl = new ScreenLocation(screenLoc[0], screenLoc[1],
					screenLoc[2], gll.textInfo);
			screenLocations.add(sl);
		}

		GL11 gl11 = (GL11) gl;

		mvmatrix = new float[16];
		projmatrix = new float[16];
		viewport = new int[4];
		gl11.glGetIntegerv(GL11.GL_VIEWPORT, viewport, 0);
		gl11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, mvmatrix, 0);
		gl11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, projmatrix, 0);
	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		super.onSurfaceChanged(gl, width, height);
	}

	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		for (LocationIcon li : icons) {
			li.loadGLTexture(gl, this.mContext, false);
		}
		myCurrIcon.loadGLTexture(gl, this.mContext, true);
		super.onSurfaceCreated(gl, config);
	}

	@Override
	public void setmListOfGeoLocations(List<GeoLocation> mListOfGeoLocations) {
		super.setmListOfGeoLocations(mListOfGeoLocations);

		float scale = 1000 * Globals.MAX_RADIUS / Globals.RADIUS;

		List<GLLocation> mListOfGLLocations = LocationUtils
				.convertFromListOfGeoLocationsToListOfGLLocations(
						this.mListOfGeoLocations, mMyCurrentGeoLocation, scale);

		LocationIconRenderer.icons = new ArrayList<LocationIcon>();
		for (GLLocation glLi : mListOfGLLocations) {
			LocationIcon tmp = new LocationIcon(glLi);
			LocationIconRenderer.icons.add(tmp);
		}
	}

	@Override
	public void setmMyCurrentGeoLocation(GeoLocation mMyCurrentGeoLocation) {
		super.setmMyCurrentGeoLocation(mMyCurrentGeoLocation);

		GeoLocation tmp = new GeoLocation(
				(float) (mMyCurrentGeoLocation.getLatitude()),
				(float) (mMyCurrentGeoLocation.getLongitude()), "Hiện tại");
		GLLocation glCurr = LocationUtils
				.convertFromGeoLocationToGLLocation(tmp);

		glCurr.x = glCurr.y = glCurr.z = 0f;
		LocationIconRenderer.myCurrIcon = new LocationIcon(glCurr);
	}

	@Override
	public void updateVertices(float azimut, GLPoint eye, GLPoint cam) {
		super.updateVertices(azimut, eye, cam);
		for (LocationIcon li : icons) {
			li.updateVertices(azimut);
		}
		myCurrIcon.updateVertices(azimut);
	}

	public void gluGetScreenLocation(GL10 gl, float xa, float ya, float za,
			float screenRadius, boolean render, float[] screenLoc) {

		float[] xyz = new float[4];
		GLU.gluProject(xa, ya, za, mvmatrix, 0, projmatrix, 0, viewport, 0,
				xyz, 0);

		xyz[1] = viewport[3] - xyz[1];

		screenLoc[0] = xyz[0];
		screenLoc[1] = xyz[1];
		screenLoc[2] = xyz[2];
	}

	public void gluGetGLOFromSO(float winX, float winY, float winZ, float[] obj) {

		float[] xyz = new float[4];
		winY = (float) viewport[3] - winY;
		GLU.gluUnProject(winX, winY, winZ, mvmatrix, 0, projmatrix, 0,
				viewport, 0, xyz, 0);
		obj[0] = xyz[0] / xyz[3];
		obj[1] = xyz[1] / xyz[3];
		obj[2] = xyz[2] / xyz[3];
		obj[3] = xyz[3] / xyz[3];

	}

	public void touchScreen(MotionEvent event) {

		float[] nearPlane = new float[4];
		gluGetGLOFromSO(event.getX(), event.getY(), -1.0f, nearPlane);

		float[] farPlane = new float[4];
		gluGetGLOFromSO(event.getX(), event.getY(), 1.0f, farPlane);

		float directionX = farPlane[0] - nearPlane[0];
		float directionY = farPlane[1] - nearPlane[1];
		float directionZ = farPlane[2] - nearPlane[2];

		GLLocation glLoc = null;
		MyOverlayItem ol = null;
		float delta = 5f;
		boolean isBroken = false;
		float t = 0.005f;
		while (t <= 1) {
			float tX = nearPlane[0] + t * directionX;
			float tY = nearPlane[1] + t * directionY;
			float tZ = nearPlane[2] + t * directionZ;

			float d = t * delta;
			float[] vrt = myCurrIcon.getVertices();
			if (min(vrt[0], vrt[6]) - tX <= d && tX - max(vrt[0], vrt[6]) <= d
					&& min(vrt[1], vrt[4]) - tY <= d
					&& tY - max(vrt[1], vrt[4]) <= d
					&& min(vrt[2], vrt[8]) - tZ <= d
					&& tZ - max(vrt[2], vrt[8]) <= d) {

				LocationIconSurfaceView lis = (LocationIconSurfaceView) Globals.locationIconView;
				lis.setMode(lis.getNone());
				GLPoint eye = new GLPoint(0f, 0f, 0f);
				GLPoint cam = new GLPoint(0f, 0f, -1f);
				Globals.planeView.getmRenderer().setCam(cam);
				Globals.planeView.getmRenderer().setEye(eye);
				Globals.locationIconView.getmRenderer().setEye(eye);
				Globals.locationIconView.getmRenderer().setCam(cam);
				Globals.locationIconView.getmRenderer().updateVertices(0f,
						null, null);
				((LocationIconRenderer) Globals.locationIconView.getmRenderer())
						.setUpdateSensor(true);
				Globals.mode = Globals.SHORT_PRESS;
				Globals.vibrator.vibrate(60);
				break;
			}

			for (int i = 0; i < icons.size(); i++) {
				LocationIcon ic = icons.get(i);
				boolean flag = true;
				if ((min(ic.getVertices()[0], ic.getVertices()[6]) - tX > d)
						|| (tX - max(ic.getVertices()[0], ic.getVertices()[6]) > d))
					flag = false;
				if ((min(ic.getVertices()[1], ic.getVertices()[4]) - tY > d)
						|| (tY - max(ic.getVertices()[1], ic.getVertices()[4]) > d))
					flag = false;
				if ((min(ic.getVertices()[2], ic.getVertices()[8]) - tZ > d)
						|| (tZ - max(ic.getVertices()[2], ic.getVertices()[8]) > d))
					flag = false;
				if (flag) {
					glLoc = ic.getGlLocation();
					if (Globals.isTrackingOnCam) {
						ol = SharingLocations.listSharingsOnCam.get(0);
					} else {
						if (Globals.currOverlayItem != null) {
							ol = Globals.currOverlayItem;
						} else {
							ol = Globals.markers.get(i);
						}
					}
					isBroken = true;
					break;
				}
			}
			t += 0.001;
			if (isBroken)
				break;
		}
		if (glLoc != null && ol != null) {
			Globals.vibrator.vibrate(30);
			this.arCamAc.viewPopup(glLoc, ol);
		}
	}

	private float max(float a, float b) {
		if (a > b)
			return a;
		return b;
	}

	private float min(float a, float b) {
		if (a > b)
			return b;
		return a;
	}
}
